/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sec_storage_ipc_proxy.h"

#include <stddef.h>

#include "logger.h"
#include "sec_storage_ipc_proxy_inner.h"

#define INPUT_BUFFER_SIZE 256
#define OUTPUT_BUFFER_SIZE 256

ResultCode SeSecStorageSetFactoryResetAuthenticationKeyProxy(IpcTransmit *transmit, FactoryResetLevel level,
    FactoryResetAuthAlgo algo, const StorageAuthKey *key)
{
    if (transmit == NULL || key == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;
    ResultCode ret = SetFactoryResetAuthenticationKeyInputToBuffer(level, algo, key, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    ret = transmit(CMD_SS_SET_FACTORY_RESET_AUTH_KEY, input, size, NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    return SUCCESS;
}

ResultCode SeSecStorageGetFactoryResetAuthenticationAlgoProxy(IpcTransmit *transmit, FactoryResetLevel level,
    FactoryResetAuthAlgo *algo)
{
    if (transmit == NULL || algo == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint32_t outSize = sizeof(uint32_t);

    ResultCode ret =
        transmit(CMD_SS_GET_FACTORY_RESET_AUTH_ALGO, (uint8_t *)&level, sizeof(uint32_t), (uint8_t *)algo, &outSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    return SUCCESS;
}

ResultCode SeSecStoragePrepareFactoryResetProxy(IpcTransmit *transmit, uint8_t *nonce, uint32_t *length)
{
    if (transmit == NULL || nonce == NULL || length == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t output[OUTPUT_BUFFER_SIZE] = {0};
    uint32_t outSize = OUTPUT_BUFFER_SIZE;

    ResultCode ret = transmit(CMD_SS_PREPARE_FACTORY_REST, NULL, 0, output, &outSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    ret = PrepareFactoryResetOutputFromBuffer(output, outSize, nonce, length);
    if (ret != SUCCESS) {
        LOG_ERROR("output from error = %u", ret);
        return ret;
    }

    return SUCCESS;
}

ResultCode SeSecStorageProcessFactoryResetProxy(IpcTransmit *transmit, FactoryResetLevel level,
    const uint8_t *credential, uint32_t length)
{
    if (transmit == NULL || credential == NULL || length == 0) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;
    ResultCode ret = ProcessFactoryResetInputToBuffer(level, credential, length, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    ret = transmit(CMD_SS_PROCESS_FACTORY_REST, input, size, NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    return SUCCESS;
}

ResultCode SeSecStorageSetToUserModeProxy(IpcTransmit *transmit, const StorageUserModeConf *config)
{
    if (transmit == NULL || config == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    ResultCode ret =
        transmit(CMD_SS_SET_TO_USER_MODE, (const uint8_t *)config, sizeof(StorageUserModeConf), NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    return SUCCESS;
}

ResultCode SeSecStorageIsSlotOperateAlgorithmSupportedProxy(IpcTransmit *transmit, SlotOperAlgo algo,
    uint32_t *available)
{
    if (transmit == NULL || available == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint32_t outSize = sizeof(uint32_t);

    ResultCode ret = transmit(CMD_SS_GET_SLOT_OPER_ALGORITHM, (const uint8_t *)&algo, sizeof(SlotOperAlgo),
        (uint8_t *)available, &outSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    return SUCCESS;
}

ResultCode SeSecStorageIsFactoryResetAlgorithmSupportedProxy(IpcTransmit *transmit, FactoryResetAuthAlgo algo,
    uint32_t *available)
{
    if (transmit == NULL || available == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint32_t outSize = sizeof(uint32_t);

    ResultCode ret = transmit(CMD_SS_GET_FACTORY_RESET_ALGORITHM, (const uint8_t *)&algo, sizeof(SlotOperAlgo),
        (uint8_t *)available, &outSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageAllocateSlotProxy(IpcTransmit *transmit, const StorageFileName *name,
    const StorageSlotAttr *slotAttr, const StorageAuthKey *slotKey)
{
    if (transmit == NULL || name == NULL || slotAttr == NULL || slotKey == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;

    ResultCode ret = AllocateSlotInputToBuffer(name, slotAttr, slotKey, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    ret = transmit(CMD_SS_ALLOCATE_SLOT, input, size, NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageGetSlotStatusProxy(IpcTransmit *transmit, const StorageFileName *name, StorageSlotStatus *status)
{
    if (transmit == NULL || name == NULL || status == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;

    ResultCode ret = GetSlotStatusInputToBuffer(name, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    uint32_t outSize = sizeof(StorageSlotStatus);

    ret = transmit(CMD_SS_GET_SLOT_STATUS, input, size, (uint8_t *)status, &outSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageWriteSlotProxy(IpcTransmit *transmit, const StorageFileName *name, const StorageAuthKey *key,
    const StorageDataArea *area, const StorageDataBuffer *data)
{
    if (transmit == NULL || name == NULL || key == NULL) {
        return INVALID_PARA_NULL_PTR;
    }
    if (area == NULL || data == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    const StorageIndicator indicator = {
        .name = name,
        .key = key,
        .area = area,
    };

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;

    ResultCode ret = WriteSlotInputToBuffer(&indicator, data, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }
    ret = transmit(CMD_SS_WRITE_SLOT, input, size, NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageReadSlotProxy(IpcTransmit *transmit, const StorageFileName *name, const StorageAuthKey *key,
    const StorageDataArea *area, StorageDataBuffer *data)
{
    if (transmit == NULL || name == NULL || key == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    if (area == NULL || data == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    const StorageIndicator indicator = {
        .name = name,
        .key = key,
        .area = area,
    };

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;

    ResultCode ret = ReadSlotInputToBuffer(&indicator, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    ret = transmit(CMD_SS_READ_SLOT, input, size, data->bufferData, &data->bufferSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageFreeSlotProxy(IpcTransmit *transmit, const StorageFileName *name, const StorageAuthKey *key)
{
    if (transmit == NULL || name == NULL || key == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;

    ResultCode ret = FreeSlotInputToBuffer(name, key, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    ret = transmit(CMD_SS_FREE_SLOT, input, size, NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageSetAllSlotsSizeProxy(IpcTransmit *transmit, const uint16_t *slotSizeArray, uint32_t arrayLength)
{
    if (transmit == NULL || slotSizeArray == NULL || arrayLength == 0) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t input[INPUT_BUFFER_SIZE] = {0};
    uint32_t size = INPUT_BUFFER_SIZE;

    ResultCode ret = SetAllSlotsSizeInputToBuffer(slotSizeArray, arrayLength, input, &size);
    if (ret != SUCCESS) {
        LOG_ERROR("input to buffer error");
        return ret;
    }

    ret = transmit(CMD_SS_SET_ALL_SLOT_SIZE, input, size, NULL, NULL);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }
    return SUCCESS;
}

ResultCode SeSecStorageGetAllSlotsSizeProxy(IpcTransmit *transmit, uint16_t *slotSizeArray, uint32_t *arrayLength)
{
    if (transmit == NULL || slotSizeArray == NULL || arrayLength == NULL) {
        return INVALID_PARA_NULL_PTR;
    }

    uint8_t output[OUTPUT_BUFFER_SIZE] = {0};
    uint32_t outSize = OUTPUT_BUFFER_SIZE;
    ResultCode ret = transmit(CMD_SS_GET_ALL_SLOT_SIZE, NULL, 0, output, &outSize);
    if (ret != SUCCESS) {
        LOG_ERROR("transmit error = %u", ret);
        return ret;
    }

    ret = GetAllSlotsSizeOutputFromBuffer(output, outSize, slotSizeArray, arrayLength);
    if (ret != SUCCESS) {
        LOG_ERROR("output from error = %u", ret);
        return ret;
    }
    return SUCCESS;
}
